package core.query;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSON;

import config.mm_config;
import config.mm_config_station_name;
import context.mm_constant;
import core.cache.mm_cache;
import core.commit.mm_commit;
import core.net.mm_http_client;
import core.reactor.mm_reactor;
import core.reactor.mm_start;
import log.mm_logger;
import utils.mm_date_util;
import utils.mm_os;
import utils.mm_random;
import utils.mm_thread;

/**
 * 查票类
 * @author dongyazhuo
 */
public class mm_query implements Runnable {

	private String TAG = mm_query.class.getSimpleName() + " : ";

	private String from_station = null;
	private String to_station = null;
	private List<String> ticke_peoples = new ArrayList<>();
	private boolean check = false;
	private int count = 0;
	private String query_url = "leftTicket/queryZ";

	private mm_http_client _mm_http_client;
	private mm_cache _mm_cache;
	private mm_config _mm_config;
	private mm_address_book _mm_address_book;
	private mm_commit _mm_commit;
	private mm_reactor _mm_reactor;

	public mm_query(mm_reactor _mm_reactor) {
		super();
		this._mm_reactor = _mm_reactor;
		this._mm_http_client = _mm_reactor._mm_http_client;
		this._mm_cache = _mm_reactor._mm_cache;
		this._mm_config = _mm_reactor._mm_config;
		this._mm_address_book = _mm_reactor._mm_address_book;
		this._mm_commit = _mm_reactor._mm_commit;
		TAG += _mm_config.getSet().getAccount_12306().getUser() + " : ";
	}

	private void init() {
		String from_station = _mm_config.getSet().getFrom_station();
		String to_station = _mm_config.getSet().getTo_station();
		List<String> ticke_peoples = _mm_config.getSet().getTicke_peoples();

		if (null == from_station || null == to_station || null == ticke_peoples || ticke_peoples.size() == 0) {
			mm_logger.e(TAG + "station or ticke_peoples set error !!!");
			mm_start.stop(_mm_reactor);
		}
		this.ticke_peoples = ticke_peoples;
		mm_config_station_name _mm_config_station_name = mm_config_station_name.instance();
		this.from_station = _mm_config_station_name.get_station_by_name(from_station);
		this.to_station = _mm_config_station_name.get_station_by_name(to_station);
		if (null == this.from_station || null == this.to_station) {
			mm_logger.e(TAG + "station file or station set error !!!");
			mm_start.stop(_mm_reactor);
		}
	}

	/**
	 * 检查用户是否在12306网站添加了联系人
	 */
	private void check_user_info() {

		// 检查日期配置
		List<String> station_dates = _mm_config.getSet().getStation_dates();
		long current = mm_date_util.getCurrentDayZero(new Date()).getTime();
		Iterator<String> iterator = station_dates.iterator();
		while (iterator.hasNext()) {
			String item = iterator.next();
			Date parse = mm_date_util.parse(item);
			if (parse.getTime() < current) {
				mm_logger.i(TAG + "date set error ,remove overdue date : " + item);
				iterator.remove();
			}
		}
		if (station_dates.isEmpty()) {
			mm_logger.e(TAG + " station dates config error!!! ");
			mm_start.stop(_mm_reactor);
		}

		if (null == from_station || null == to_station || null == ticke_peoples || ticke_peoples.size() == 0) {
			init();
		}
		if (_mm_config.getSet().getAccount_12306().isQuery()) {
			mm_logger.i("login_mode is query.");
			return;
		} else {
			do {
				// 检查用户是否登陆
				long l = _mm_cache.get(_mm_cache.user_time);
				if (l < -1 || l == 0) {// 说明已经过期
					mm_thread.sleep(1000);
				} else {
					break;
				}
			} while (true);

		}
		if (check) {
			return;
		}

		List<String> user_names = _mm_address_book.get_user_names();
		for (String name : ticke_peoples) {
			if (!user_names.contains(name)) {
				mm_logger.w(TAG + name + " ticket user is not collect ,please login to the official website first to add !!!");
			}
		}
		this.check = true;
		mm_logger.i(TAG + "query check finish !!!");
	}

	public void query() {
		check_user_info();
		while (true) {
			_mm_reactor._mm_login.check_sleep_time();

			do_query();
		}
	}

	private void do_query() {

		if (!_mm_config.isStart()) {
			// 结束登陆守护线程
			mm_logger.w(TAG + "config file is changed , start is false !!!");
			mm_start.stop(_mm_reactor);
		}

		if (null == from_station || null == to_station || null == ticke_peoples || ticke_peoples.size() == 0) {
			init();
		}

		int order_model = _mm_config.getOrder_model();
		if (1 == order_model) {
			String open_time = _mm_config.getOpen_time();
			Date date = mm_date_util.parseCurrentDay(open_time);
			if (date.getTime() >= System.currentTimeMillis()) {
				mm_thread.sleep(200);
				return;
			}
		}
		List<String> station_dates = _mm_config.getSet().getStation_dates();
		for (String station_date : station_dates) {
			try {
				mode_2_query(station_date);
				count++;
			} catch (Exception e) {
				mm_logger.e(TAG + station_date + " query error !!!" + e.getMessage());
				e.printStackTrace();
			}
			long millis = mm_random.next_int(2500) + 500L;
			mm_logger.i(TAG + "第 " + count + " 次查询 . 间隙休息: " + millis + " ms. ");
			mm_thread.sleep(millis);
		}
	}

	/**
	 * 第二种模式查询
	 * @param station_date
	 */
	private void mode_2_query(String station_date) {
		clear_scr();
		Map<String, Object> url = _mm_config.getUrl_config().get("select_url");
		String req_url = url.get("req_url").toString();
		req_url = String.format(req_url, query_url, station_date, from_station, to_station);
		Map<String, Object> url_request = new HashMap<>(url);
		url_request.put("req_url", req_url);
		HashMap r = (HashMap) _mm_http_client.send(url_request, new HashMap<>());
		if (null != r && null != r.get("c_url")) {
			query_url = r.get("c_url").toString();
			mm_logger.i(TAG + " query url reset : " + query_url);
			return;
		}
		if (null == r.get("data")) {
			String from_station = _mm_config.getSet().getFrom_station();
			String to_station = _mm_config.getSet().getTo_station();
			String format = String.format("{%s}-{%s} 车次坐席查询为空,ip网络异常，可能是时间配置未正确，查询url: https://kyfw.12306.cn%s, 可以手动查询是否有票",
					from_station, to_station, req_url);
			mm_logger.w(TAG + format);
			return;
		}
		HashMap result_data = JSON.parseObject(r.get("data").toString(), HashMap.class);
		Object result_result = result_data.get("result");
		if (null != result_result) {
			ArrayList<String> result_list = JSON.parseObject(result_result.toString(), ArrayList.class);
			if (null != result_list && result_list.size() > 0) {
				printf(result_list, station_date);
				mm_query_result check_result = check(result_list, station_date);

				if (check_result.status && !_mm_config.getSet().getAccount_12306().isQuery()) {
					_mm_commit.commit(check_result);
				}
			} else {
				String log = String.format("车次配置信息有误，或者返回数据异常，请检查 {%s}", r.toString());
				mm_logger.e(TAG + log);
			}
		} else {
			String log = String.format("车次配置信息有误，或者返回数据异常，请检查 {%s}", r.toString());
			mm_logger.e(TAG + log);
		}
	}

	private void printf(ArrayList<String> result_list, String station_date) {
		String from_station = _mm_config.getSet().getFrom_station();
		String to_station = _mm_config.getSet().getTo_station();
		mm_logger.i(TAG + "*****************************************************" + station_date
				+ "*****" + from_station + "--->" + to_station + "************************************************");

		for (String ticket_info : result_list) {
			String[] split = ticket_info.split("\\|");
			String checi = split[3];
			String chufa_shijian = split[8];
			String daoda_shijian = split[9];
			String lishi_shijian = split[10];
			String format = String.format("车次:%s\t出发时间:%s 到达时间：%s 历时:%s ", checi, chufa_shijian, daoda_shijian,
					lishi_shijian);
			Set<String> keys = mm_constant.seat_conf.keySet();
			StringBuilder sb = new StringBuilder(format);
			for (String k : keys) {
				Integer v = mm_constant.seat_conf.get(k);
				String status = split[v].equals("") ? "-" : split[v];
				sb.append(k + ":" + status + "\t");
			}
			mm_logger.i(TAG + sb.toString());
		}
		mm_logger.i(TAG + "*****************************************************" + station_date
				+ "*****" + from_station + "--->" + to_station + "************************************************");
		mm_logger.i(TAG);
	}

	/**
	 * 根据条件检查是否可预定
	 * @param result_list
	 * @param station_date
	 * @return
	 */
	private mm_query_result check(ArrayList<String> result_list, String station_date) {
		for (String ticket_info : result_list) {
			String[] split = ticket_info.split("\\|");
			String checi = split[3];
			String chufa_shijian = split[8];
			String daoda_shijian = split[9];
			String lishi_shijian = split[10];
			// 过滤列车类型
			List<String> train_types = _mm_config.getSet().getTrain_types();
			String train_type = checi.split("")[0];

			if (!train_types.contains(train_type)) {
				if (!train_types.contains("O")) {
					continue;
				}
			}

			// 如果根据车次+座位预定
			if (!_mm_config.getSet().isBy_time()) {
				List<String> station_trains = _mm_config.getSet().getStation_trains();
				if (station_trains.contains(checi)) {
					mm_query_result _mm_query_result = create_result(station_date, split);
					if (_mm_query_result.status) {
						return _mm_query_result;
					}
				}
			} else {
				// 根据时间与座位预定
				boolean time = time_compare(chufa_shijian, daoda_shijian);
				if (time) {// 时间符合
					mm_query_result _mm_query_result = create_result(station_date, split);
					if (_mm_query_result.status) {
						return _mm_query_result;
					}
				}
			}
		}
		return new mm_query_result();
	}

	private mm_query_result create_result(String station_date, String[] split) {
		int seat = seat_compare(split);
		if (seat != -1) {
			int is_more_ticket_num = get_is_more_ticket_num(split[seat]);
			if (is_more_ticket_num != -1) {
				return new mm_query_result(split[0], split[2], split[3], station_date, split[6], split[7],
						seat, split[12], split[15], mm_constant.SUCCESS_CODE, is_more_ticket_num, "", true);
			}
		}
		return new mm_query_result();
	}

	/**
	 * 座位比较器
	 * @param split
	 * @return
	 */
	private Integer seat_compare(String[] split) {
		Set<String> keys = mm_constant.seat_conf.keySet();
		for (String k : keys) {
			Integer v = mm_constant.seat_conf.get(k);
			if (split[v].equals("无")) {
				continue;
			}
			boolean zuowei = split[v].equals("有") || Integer.parseInt(split[v].equals("") ? "0" : split[v]) > 0;// 座位状态
			if (zuowei) {
				List<String> set_type = _mm_config.getSet().getSet_type();
				if (set_type.contains(k)) {
					return v;
				}
			}
		}
		return -1;
	}

	/**
	 * 查询最多可购买
	 * @param split
	 * @param seat
	 * @return
	 */
	private int get_is_more_ticket_num(String seat_status) {
		int num = 0;
		if ("有".equals(seat_status)) {
			num = 999;// 默认最多可购买999张
		} else {
			num = Integer.parseInt(seat_status);
		}
		int peoples_size = _mm_config.getSet().getTicke_peoples().size();

		if (num < peoples_size) {
			mm_logger.w(TAG + "余票不足 !!!");
			boolean more_ticket = _mm_config.getSet().isMore_ticket();
			if (more_ticket) {
				return num;
			}
			if (!more_ticket) {
				mm_logger.w(TAG + "余票不足 ,余票数小于乘车人数，当前设置不提交，放弃此次提交机会!!!");
				return -1;
			}
		}

		return peoples_size;
	}

	/**
	 * 时间比较器
	 * @param begin
	 * @param end
	 * @return
	 */
	private boolean time_compare(String begin, String end) {
		String zao = _mm_config.getSet().getDeparture_time();
		String wan = _mm_config.getSet().getArrival_time();
		// 比较开始时间(小时)
		if (Integer.parseInt(begin.split(":")[0]) >= Integer.parseInt(zao.split(":")[0])) {
			// 比较开始时间(分钟)
			if (Integer.parseInt(begin.split(":")[1]) >= Integer.parseInt(zao.split(":")[1])) {
				// 比较结束时间(小时)
				if (Integer.parseInt(end.split(":")[0]) <= Integer.parseInt(wan.split(":")[0])) {
					// 比较开始时间(分钟)
					if (Integer.parseInt(zao.split(":")[1]) <= Integer.parseInt(wan.split(":")[1])) {
						return true;
					}
				}
			}
		}
		// begin.split(":")[1];
		return false;
	}

	private void clear_scr() {

		try {
			if (mm_os.isLinux()) {
				String command = "clear";
				Runtime.getRuntime().exec(command);
			}
			if (mm_os.isWindows()) {
				String command = "cls";
				Runtime.getRuntime().exec(command);
			}
		} catch (Exception e) {
		}

	}

	@Override
	public void run() {
		query();
	}

}
